Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×

[Looking for Help][API]<-(I Think) Change Attribute With Sheetworker

Hello everyone. I am very new to API and this kind of programming in general (though I am getting the hang of the HTML and CSS) and I am attempting to have a change in one attribute cause another attribute to have a different value based on how much it has changed. The basic idea is that my sheet has an exhaustion (that you can change by 1 up to the max) and a max exhaustion value. A disadvantage die (d4) is added to a roll if your exhaustion is equal to half your exhaustion (so if you have 2 exhaustion, and 4 max, you have a d4 of disadvantage), and this die type is increased (d6, d8, d10, d12) for every 2 levels you go above half your exhaustion (until you get to max, and then you are incapacitated). My current script was cobbled together from a few different API examples with probably some misunderstanding of how the scripts work together and is below. on("change:exhaustion_level", function(eventinfo) { const newValue = parseInt(eventinfo.newValue) || 0, previousValue = parseInt(eventinfo.previousValue) || 0; let update = {}; if (newValue === 0) { setAttrs({ exhaustion_tracking: 0 }); } else if (newValue == (getAttrByName(exhaustion_max) / 2)) { setAttrs({ exhaustion_tracking: d4 }); } else if (newValue == ((getAttrByName(exhaustion_max) / 2) + 2) &amp;&amp; newValue &lt; (getAttrByName(exhaustion_max)) { setAttrs({ exhaustion_tracking: d6 }); } else if (newValue == ((getAttrByName(exhaustion_max) / 2) + 4) &amp;&amp; newValue &lt; (getAttrByName(exhaustion_max)) { setAttrs({ exhaustion_tracking: d8 }); } else if (newValue == ((getAttrByName(exhaustion_max) / 2) + 6) &amp;&amp; newValue &lt; (getAttrByName(exhaustion_max)) { setAttrs({ exhaustion_tracking: d10 }); } else if (newValue == ((getAttrByName(exhaustion_max) / 2) + 8) &amp;&amp; newValue &lt; (getAttrByName(exhaustion_max)) { setAttrs({ exhaustion_tracking: d12 }); } else { setAttrs({ exhaustion_tracking: incap. }); }; setAttrs(update, {silent: true}); }); I am pretty sure the setAttrs is updating the attribute, or at least it should if the values are passed in correctly. The code that takes the updated values is below, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;div class="subcontainer" style="height: min-content; width: 70px;"&gt; &lt;div class="top"&gt; &lt;span style="font-size: 12px;"&gt;Current&lt;/span&gt; &lt;input type="number" name="attr_exhaustion" title="@{exhaustion}" class="sheet-biomenu" min = "0" max="@{exhaustion_max}" step="1"&gt; &lt;/div&gt; &lt;span style="font-size: 12px;"&gt;Total&lt;/span&gt; &lt;input type="number" name="attr_exhaustion_max" title="@{exhaustion_max}" class="sheet-biomenu" disabled="true" value="(@{physical_injuries_max}) + (@{mental_injuries_max})"&gt; &lt;/div&gt; &lt;span&gt;Toggle Exh. Tracking:&lt;/span&gt; &lt;div&gt; &lt;input class="toggle-left" name="attr_exhaustion_effect_toggle" type="radio" title="@{exhaustion_disadvantage}" value="0" checked="checked"/&gt;&lt;span&gt;Off&lt;/span&gt; &lt;input class="toggle-right" name="attr_exhaustion_effect_toggle" type="radio" title="@{exhaustion_disadvantage}" value="1@{tracked_exhaustion}!"/&gt;&lt;span&gt;On&lt;/span&gt; &lt;/div&gt; &lt;div&gt;Dis. Level:&lt;input type="number" name="attr_exhaustion_tracking" title="@{tracked_exhaustion}" class = "sheet-biomenu" disabled = "true" value="0"&gt; &lt;/div&gt; I am supposed to be passing in the values of exhaustion and max exhaustion, checking if the tracking is toggled through the radio selection, and then updating the die supposed to be rolled and the tracking field (the Dis. Level input which should show the dice value as d4, d6, d8, d10, d12). But after a lot of trial and error I can't tell if either is happening, or if my underlying script just doesn't work, or maybe even if the premise I am going for won't work. Any help is appreciated.
1630938451

Edited 1630938527
Hello, If I understood how the sheetworker does things, it won't understand the value of your "exhaustion_max" as the value is " (@{physical_injuries_max}) + (@{mental_injuries_max}) ". This should work if your exhaustion_max is a number or is calculated with the sheetworker on("change:exhaustion_lvl", function() { &nbsp;&nbsp;&nbsp;&nbsp;getAttrs(["exhaustion_lvl", "exhaustion_max"], function(values) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const output = {}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const exhaust = parseInt(values["exhaustion_lvl"]) || 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const maxExhaust = parseInt(values["exhaustion_max"]) || 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (parseInt(values["exhaustion_lvl"]) == 0) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output["exhaustion_tracking"] = 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (exhaust == (maxExhaust / 2)) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output["exhaustion_tracking"] = "1D4"; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (exhaust == (maxExhaust / 2 + 2) &amp;&amp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output["exhaustion_tracking"] = "1D6"; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (exhaust == (maxExhaust / 2 + 4) &amp;&amp; (exhaust &lt; maxExhaust)) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output["exhaustion_tracking"] = "1D8"; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (exhaust == (maxExhaust / 2 + 6) &amp;&amp; (exhaust &lt; maxExhaust)) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output["exhaustion_tracking"] = "1D10"; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (exhaust == (maxExhaust / 2 + 8) &amp;&amp; (exhaust &lt; maxExhaust)) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output["exhaustion_tracking"] = "1D12"; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output["exhaustion_tracking"] = "Incap." &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs(output); &nbsp;&nbsp;&nbsp;&nbsp;}); });
1630942429
GiGs
Pro
Sheet Author
API Scripter
The previous poster is correct that sheet worked cannot work with disabled attributes. you'd need to use a sheet worker to calculate that attribute, and change disabled="true" to readonly . You also cant use the getAttrByName function in a sheet worker - that's an API script function. The worker in Eggoer's post (sorry I don't know how to do the special o symbol) looks good, but it carries over what I think may be an error from the original worker. The if statement looks like it will have "holes". Take this section: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (exhaust == (maxExhaust / 2)) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output["exhaustion_tracking"] = "1D4"; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (exhaust == (maxExhaust / 2 + 2) &amp;&amp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output["exhaustion_tracking"] = "1D6"; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} What happened is exhaust = maxExhaust / 2 + 1? Each of the == in this worker I think should be replaced by &lt;= . Also the first line of the if statement should be &nbsp;if (exhaust == 0) { the parseInt isn't needed there.
Thanks for the replies, I've attempted to put in what people have suggested, and I changed the autocalculating fields to what I hope are sheetworkers that do the same thing to readonly attributes, but nothing seems to be happening with whatever I try it, no matter what kind of console outputs I try. I encountered a "Debounced init page!" in the console a few times but I don't know if it is related.&nbsp; For reading in values, I am using a selection field (which may be the problem itself, but the values are numbers and there are no errors in that regard).&nbsp; &lt;span class="sheet-statmenu"&gt;&lt;select name="attr_willpower" title="@{willpower}" class="sheet-traitdie" value="4"&gt; &lt;option value="4"&gt;d4&lt;/option&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;option value="6"&gt;d6&lt;/option&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;option value="8"&gt;d8&lt;/option&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;option value="10"&gt;d10&lt;/option&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;option value="12"&gt;d12&lt;/option&gt; &lt;/select&gt;&lt;/span&gt; That is an example of all the attributes I have as inputs. Which get transferred to roll checks if a checkbox is checked.&nbsp; &lt;span&gt;&lt;input type="checkbox" name="attr_willpowercheck" value="1d@{willpower}!"/&gt;&lt;/span&gt; These do work for things like rolls which I calculate like the code below. {{Result=[[@{agilitycheck} + @{charismacheck} + @{dexteritycheck} + @{cunningcheck} + @{constitutioncheck} + @{willpowercheck} + @{strengthcheck} + @{luckcheck} + @{advantagecheck} + @{extra_advantagecheck} - @{disadvantagecheck} - @{extra_disadvantagecheck}]]}} Back to the fields calculating exhaustion, I then am using sheetworkers to calculate the values I previously had as autocalc fields. &lt;script type = "text/worker"&gt; on("change:willpower change:constitution sheet:opened", function() { getAttrs(["willpower", "constitution"], function(values) { let will = parseInt(values["willpower"]) || 0; let con = parseInt(values["constitution"]) || 0; let mentInjMax = will / 2; let physInjMax = con / 2; setAttrs({ mental_injuries_max: mentInjMax, physical_injuries_max: physInjMax, blood_points_max: con }); }); }); &lt;/script&gt; &lt;script type = "text/worker"&gt; on("change:willpower change:constitution sheet:opened", function() { getAttrs(["mental_injuries_max", "physical_injuries_max"], function(values) { let mentInjMax = parseInt(values["mental_injuries_max"]) || 0; let physInjMax = parseInt(values["physical_injuries_max"]) || 0; let exhMax = mentInjMax + physInjMax; setAttrs({ exhaustion_max: exhMax }); }); }); &lt;/script&gt; &lt;script&gt; on("change:exhaustion_lvl", function() { getAttrs(["exhaustion_lvl", "exhaustion_max"], function(values) { const output = {}; const exhaust = parseInt(values["exhaustion_lvl"]) || 0; const maxExhaust = parseInt(values["exhaustion_max"]) || 0; if (exhaust == 0) { output["exhaustion_tracking"] = 0; } else if (exhaust &lt;= (maxExhaust / 2)) { output["exhaustion_tracking"] = "1D4"; } else if (exhaust &lt;= (maxExhaust / 2 + 2) &amp;&amp; { output["exhaustion_tracking"] = "1D6"; } else if (exhaust &lt;= (maxExhaust / 2 + 4) &amp;&amp; (exhaust &lt; maxExhaust)) { output["exhaustion_tracking"] = "1D8"; } else if (exhaust &lt;= (maxExhaust / 2 + 6) &amp;&amp; (exhaust &lt; maxExhaust)) { output["exhaustion_tracking"] = "1D10"; } else if (exhaust &lt;= (maxExhaust / 2 + 8) &amp;&amp; (exhaust &lt; maxExhaust)) { output["exhaustion_tracking"] = "1D12"; } else { output["exhaustion_tracking"] = "Incap." } setAttrs(output); }); }); &lt;/script&gt; And I should have fixed the issues in the code that Eggoer gave me (much appreciated to both of you). But it doesn't seem to take or change any values. I'm not sure if my parseInt fields are weird as the sheetworker help page had a slightly different format (which also didn't work when I tried) but it may just be that my values aren't being passed in.&nbsp; They all should be showing up in fields shown in code below.&nbsp; &lt;input type="number" name="attr_physical_injuries_max" title="@{physical_injuries_max}" class = "sheet-biomenu" readonly = "readonly" value = ""&gt; &lt;input type="number" name="attr_mental_injuries_max" title="@{mental_injuries_max}" class = "sheet-biomenu" readonly = "readonly" value = ""&gt; &lt;input type="number" name="attr_exhaustion_tracking" title="@{tracked_exhaustion}" class = "sheet-biomenu" readonly = "readonly"&gt; &lt;input type="number" name="attr_blood_points_max" title="@{blood_points_max}" class="sheet-biomenu" readonly = "readonly" value=""&gt; I didn't know if I needed the value = " " as a placeholder or not, and I'm not sure if the input fields are the issue. If the initial selection fields are the problem, I'm not sure how I'll change the sheet as it will cause so many changes to how the whole thing looks/functions.&nbsp;
1630947268

Edited 1630947466
Andreas J.
Forum Champion
Sheet Author
Translator
Don't put your sheetworkers in multiple &lt;script type = "text/worker"&gt; , that's a pretty likely cause of problems. It's sheetworker 101: <a href="https://wiki.roll20.net/Sheet_Worker_Scripts#Structure_of_a_Sheetworker" rel="nofollow">https://wiki.roll20.net/Sheet_Worker_Scripts#Structure_of_a_Sheetworker</a> &lt;input type="number" name="attr_physical_injuries_max" title="@{physical_injuries_max}" class = "sheet-biomenu" readonly = "readonly" value = ""&gt; I'd recommend being more consistent with your code and changing the above to this: &lt;input type="number" name="attr_physical_injuries_max" title="@{physical_injuries_max}" class="sheet-biomenu" readonly value=""&gt; Don't think it's a good idea to leave spaces around = ,
Sorry about that, I originally had the two under one I just switched to separating and doing multiple out of habit from other languages, that is my bad, they still aren't working though, including the original I had for changing pages.&nbsp; &lt;!--Text workers for changing tabs on the sheet and updating exhaustion--&gt; &lt;script type = "text/worker"&gt; const buttonlist = ["character","journal","configuration"]; buttonlist.forEach(button =&gt; { on(`clicked:${button}`, function() { setAttrs({ sheetTab: button }); }); }); //Changing max injuries and blood points on("change:willpower change:constitution sheet:opened", function() { getAttrs(["willpower", "constitution"], function(values) { let will = parseInt(values["willpower"]) || 0; let con = parseInt(values["constitution"]) || 0; let mentInjMax = will / 2; let physInjMax = con / 2; setAttrs({ mental_injuries_max: mentInjMax, physical_injuries_max: physInjMax, blood_points_max: con }); }); }); //Changes max exhaustion on("change:willpower change:constitution sheet:opened", function() { getAttrs(["mental_injuries_max", "physical_injuries_max"], function(values) { let mentInjMax = parseInt(values["mental_injuries_max"]) || 0; let physInjMax = parseInt(values["physical_injuries_max"]) || 0; let exhMax = mentInjMax + physInjMax; setAttrs({ exhaustion_max: exhMax }); }); }); //Changes effects based on exhaustion level and max exhaustion on("change:exhaustion_lvl", function() { getAttrs(["exhaustion_lvl", "exhaustion_max"], function(values) { const output = {}; const exhaust = parseInt(values["exhaustion_lvl"]) || 0; const maxExhaust = parseInt(values["exhaustion_max"]) || 0; if (exhaust == 0) { output["exhaustion_tracking"] = 0; } else if (exhaust &lt;= (maxExhaust / 2)) { output["exhaustion_tracking"] = "1D4"; } else if (exhaust &lt;= (maxExhaust / 2 + 2) &amp;&amp; { output["exhaustion_tracking"] = "1D6"; } else if (exhaust &lt;= (maxExhaust / 2 + 4) &amp;&amp; (exhaust &lt; maxExhaust)) { output["exhaustion_tracking"] = "1D8"; } else if (exhaust &lt;= (maxExhaust / 2 + 6) &amp;&amp; (exhaust &lt; maxExhaust)) { output["exhaustion_tracking"] = "1D10"; } else if (exhaust &lt;= (maxExhaust / 2 + 8) &amp;&amp; (exhaust &lt; maxExhaust)) { output["exhaustion_tracking"] = "1D12"; } else { output["exhaustion_tracking"] = "Incap." } setAttrs(output); }); }); &lt;/script&gt; Looking at others this seems to be how these work all under one but I am not sure, and this seems to have broken my original sheetworker for just changing pages even if I delete all the ones I made for tracking exhaustion.
1630952891

Edited 1630953498
Andreas J.
Forum Champion
Sheet Author
Translator
I ran some checks on your javascript and it gave an error: JSC_PARSE_ERROR: Parse error. '}' expected at line 59 character 18 output["exhaustion_tracking"] = "1D6"; seems you have incomplete conditional here: else if (exhaust &lt;= (maxExhaust / 2 + 2) &amp;&amp; { output["exhaustion_tracking"] = "1D6"; } And while roll20 seems to work with writing html like "&lt;script type = "text/worker" &gt;" instead of &lt;script type="text/worker" &gt;, I recommend you follow best practice in writing your code, in case roll20 is more strict than baseline HTML. Keeping it consistent also makes it easier to spot mistakes, when code validation doesn't. There are known Roll20 bugs where roll20 is more strict and specific than what general HTML needs to be, like the single quote issue with roll templates: <a href="https://wiki.roll20.net/Building_Character_Sheets/Roll_Templates#Restrictions" rel="nofollow">https://wiki.roll20.net/Building_Character_Sheets/Roll_Templates#Restrictions</a>
1630953317
GiGs
Pro
Sheet Author
API Scripter
Andreas J. said: And while roll20 seems to work with writing html like &lt;script type = "text/worker"&gt; instead of &lt;script type="text/worker"&gt; , I recommend you follow best practice in writing your code, in case roll20 is more strict than baseline HTML. Keeping it consistent also makes it easier to spot mistakes, when code validation doesn't. I've definitely seen failures before with spaces there. HTMl and javascript are permissive with spaces in most places, but that one has caused me failures in the past.
1630953792

Edited 1630953966
Andreas J.
Forum Champion
Sheet Author
Translator
I've definitely seen failures before with spaces there. I've never seen roll20 sheet code with that much spaces, so haven't encountered any bugs with it either, but it really sticks out to me as a potential roll20 issue. Do you have any example we could list on <a href="https://wiki.roll20.net/BCS/Bugs" rel="nofollow">https://wiki.roll20.net/BCS/Bugs</a> ? Guess I just follow code styleguides so often that I'm not even aware of how exactly how fast and loose you can do with HTML :D Google HTML/CSS Style Guide, for those interested.
Andreas J. said: I ran some checks on your javascript and it gave an error: JSC_PARSE_ERROR: Parse error. '}' expected at line 59 character 18 output["exhaustion_tracking"] = "1D6"; seems you have incomplete conditional here: else if (exhaust &lt;= (maxExhaust / 2 + 2) &amp;&amp; { output["exhaustion_tracking"] = "1D6"; } And while roll20 seems to work with writing html like "&lt;script type = "text/worker" &gt;" instead of &lt;script type="text/worker" &gt;, I recommend you follow best practice in writing your code, in case roll20 is more strict than baseline HTML. Keeping it consistent also makes it easier to spot mistakes, when code validation doesn't. There are known Roll20 bugs where roll20 is more strict and specific than what general HTML needs to be, like the single quote issue with roll templates: <a href="https://wiki.roll20.net/Building_Character_Sheets/Roll_Templates#Restrictions" rel="nofollow">https://wiki.roll20.net/Building_Character_Sheets/Roll_Templates#Restrictions</a> I fixed that and everything is now working perfectly! And I'll be sure to both bookmark that checker for javascript and remember to be more careful with my html in roll20. I've just had spacing drilled into me for code readability (usually in classes) so I default to that usually. Thanks for your help and everyone else's as well.&nbsp;
1630956931

Edited 1630957014
GiGs
Pro
Sheet Author
API Scripter
I'm not following the thread closely, but these two sheet workers should be combined: //Changing max injuries and blood points on("change:willpower change:constitution sheet:opened", function() { getAttrs(["willpower", "constitution"], function(values) { let will = parseInt(values["willpower"]) || 0; let con = parseInt(values["constitution"]) || 0; let mentInjMax = will / 2; let physInjMax = con / 2; setAttrs({ mental_injuries_max: mentInjMax, physical_injuries_max: physInjMax, blood_points_max: con }); }); }); //Changes max exhaustion on("change:willpower change:constitution sheet:opened", function() { getAttrs(["mental_injuries_max", "physical_injuries_max"], function(values) { let mentInjMax = parseInt(values["mental_injuries_max"]) || 0; let physInjMax = parseInt(values["physical_injuries_max"]) || 0; let exhMax = mentInjMax + physInjMax; setAttrs({ exhaustion_max: exhMax }); }); }); like so &nbsp; on ( "change:willpower&nbsp;change:constitution&nbsp;sheet:opened" ,&nbsp; function ()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; getAttrs ([ "willpower" ,&nbsp; "constitution" ],&nbsp; function ( values )&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; will &nbsp;=&nbsp; parseInt ( values [ "willpower" ])&nbsp;||&nbsp; 0 ; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; con &nbsp;=&nbsp; parseInt ( values [ "constitution" ])&nbsp;||&nbsp; 0 ; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; mentInjMax &nbsp;=&nbsp; will &nbsp;/&nbsp; 2 ; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; physInjMax &nbsp;=&nbsp; con &nbsp;/&nbsp; 2 ; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; exhMax &nbsp;=&nbsp; mentInjMax &nbsp;+&nbsp; physInjMax ; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setAttrs ({&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mental_injuries_max : &nbsp; mentInjMax , &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; physical_injuries_max : &nbsp; physInjMax , &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blood_points_max : &nbsp; con , &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exhaustion_max : &nbsp; exhMax &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;}); }); When you have two sheet workers that have exactly the same change line, it's best to combine them. Also those will/2 and con/2 calculations make me cock my head quizzically. Should you be rounding off to a whole number either there or on the enhMax attribute?
1630957389

Edited 1630957410
GiGs
Pro
Sheet Author
API Scripter
Andreas J. said: I've definitely seen failures before with spaces there. I've never seen roll20 sheet code with that much spaces, so haven't encountered any bugs with it either, but it really sticks out to me as a potential roll20 issue. Do you have any example we could list on <a href="https://wiki.roll20.net/BCS/Bugs" rel="nofollow">https://wiki.roll20.net/BCS/Bugs</a> ? The example is simply using &lt;script type = "text/worker"&gt; The spaces there either side of the = will force the sheet block to stop working in my experience, and you need to use &lt;script type="text/worker"&gt;
Oh, I actually already combined those as it worked better that way, definitely makes sense to combine them. Since all the dice types used are even (con and will can only be 4, 6, 8 10, and 12), rounding is unnecessary in either situation as division by two will always be a whole number. If I was adding one to them for some reason (or using the player input exhaustion for some other calculation) I would probably be frustrated for a few hours at the thing not working, and then realize that I needed to round.&nbsp;
GiGs said: Andreas J. said: I've definitely seen failures before with spaces there. I've never seen roll20 sheet code with that much spaces, so haven't encountered any bugs with it either, but it really sticks out to me as a potential roll20 issue. Do you have any example we could list on <a href="https://wiki.roll20.net/BCS/Bugs" rel="nofollow">https://wiki.roll20.net/BCS/Bugs</a> ? The example is simply using &lt;script type = "text/worker"&gt; The spaces there either side of the = will force the sheet block to stop working in my experience, and you need to use &lt;script type="text/worker"&gt; Yeah, realized after more carefully reading all the documentation that the spaces may have been a part of my issues.&nbsp;